package pl.gigiel.jme.behaviour.boidbody.factory;

import java.lang.reflect.Constructor;

import pl.gigiel.behaviour.IBoid;
import pl.gigiel.behaviour.IBoidFactory;
import pl.gigiel.behaviour.IBoidFeatures;
import pl.gigiel.behaviour.IEnvironment;
import pl.gigiel.behaviour.ISteerManager;
import pl.gigiel.behaviour.exception.BehaviourException;
import pl.gigiel.jme.behaviour.IBoidBody;
import pl.gigiel.jme.behaviour.IBoidBodyFactory;

import com.jme.scene.Node;

public class BoidBodyFactory implements IBoidBodyFactory {
	private static IBoidBodyFactory boidBodyFactory;
	private Node rootNode;
	private IBoidFactory boidFactory;

	private BoidBodyFactory(Node rootNode, IBoidFactory boidFactory) {
		this.rootNode = rootNode;
		this.boidFactory = boidFactory;
	}

	public static IBoidBodyFactory getInstance(Node rootNode, IBoidFactory boidFactory) {
		if (boidBodyFactory == null) {
			boidBodyFactory = new BoidBodyFactory(rootNode, boidFactory);
		}
		return boidBodyFactory;
	}

	@Override
	public <T extends IBoid, W extends IBoidBody> IBoidBody createBoidBody(Class<T> boidClass, Class<W> boidBodyClass, IEnvironment environment, ISteerManager steerManager, IBoidFeatures features) throws BehaviourException {
		IBoid boid = null;
		IBoidBody boidBody = null;
		try {
			boid = boidFactory.createBoid(boidClass, environment, steerManager, features);
			boidBody = create(boidBodyClass, rootNode, boid);
		} catch (Exception e) {
			throw new BehaviourException(e);
		}
		boidBody.init();
		return boidBody;
	}

	private <T extends IBoidBody> IBoidBody create(Class<T> boidBodyClass, Node rootNode, IBoid boid) throws BehaviourException {
		IBoidBody boidBody = null;
		try {
			Constructor<T> constructor = boidBodyClass.getConstructor(Node.class, IBoid.class);
			boidBody = constructor.newInstance(rootNode, boid);
		} catch (Exception e) {
			throw new BehaviourException(e);
		}
		return boidBody;
	}
}
